function InitItemEvents()
	ListenToGameEvent("dota_item_picked_up", Dynamic_Wrap(Survival, "OnItemPickedUp"), Survival)

	CustomGameEventManager:RegisterListener("swap_items", function(id, ...) Dynamic_Wrap(Survival, "OnSwapItems")(Survival, ...) end)
	CustomGameEventManager:RegisterListener("drop_item", function(id, ...) Dynamic_Wrap(Survival, "OnDropItem")(Survival, ...) end)
	CustomGameEventManager:RegisterListener("give_item", function(id, ...) Dynamic_Wrap(Survival, "OnGiveItem")(Survival, ...) end)
	CustomGameEventManager:RegisterListener("open_chest", function(id, ...) Dynamic_Wrap(Survival, "OnOpenChest")(Survival, ...) end)
	CustomGameEventManager:RegisterListener("quick_move_item", function(id, ...) Dynamic_Wrap(Survival, "OnQuickMoveItem")(Survival, ...) end)
	CustomGameEventManager:RegisterListener("equip_or_unequip_equipment", function(id, ...) Dynamic_Wrap(Survival, "OnEquipOrUnequipEquipment")(Survival, ...) end)
end

--GameEvents
function Survival:OnItemPickedUp(events)
	local unit = EntIndexToHScript(events.HeroEntityIndex):GetParentEntity()
	local item = EntIndexToHScript(events.ItemEntityIndex)
	local position = item:GetContainer():GetAbsOrigin()

	if item.GetParentEntity == nil then
		local item_entity = Item()
		item_entity:SetItem(item)

		item = item_entity
	else
		item = item:GetParentEntity()
	end

	if not unit:AddItem(item) then
		unit:DropItemAtPositionImmediate(item, position)
	end

end

--CustomGameEvents
function Survival:OnSwapItems(events)
	local playerId = events.PlayerID

	local container1 = GetEntityByIndex(events.containerIndex1)
	if container1 == nil then
		return
	end
	local slotIndex1 = events.slotIndex1

	local container2 = GetEntityByIndex(events.containerIndex2)
	local slotIndex2 = events.slotIndex2

	local isShiftDown = events.isShiftDown == 1
	local isCtrlDown = events.isCtrlDown == 1

	container1:SwapItems(slotIndex1, container2, slotIndex2, isShiftDown, isCtrlDown)
end

function Survival:OnDropItem(events)
	local playerId = events.PlayerID

	local container = GetEntityByIndex(events.containerIndex)
	if container == nil then
		return
	end

	local item = EntIndexToHScript(events.itemIndex)
	if item == nil or item.GetParentEntity == nil then
		return
	end
	item = item:GetParentEntity()

	local position = Vector(events.position["0"], events.position["1"], events.position["2"])

	local isShiftDown = events.isShiftDown == 1
	local isCtrlDown = events.isCtrlDown == 1

	container:DropItemAtPosition(position, item, isShiftDown, isCtrlDown)
end

function Survival:OnGiveItem(events)
	local playerId = events.PlayerID

	local container = GetEntityByIndex(events.containerIndex)
	if container == nil then
		return
	end

	local item = EntIndexToHScript(events.itemIndex)
	if item == nil or item.GetParentEntity == nil then
		return
	end
	item = item:GetParentEntity()

	local target = EntIndexToHScript(events.targetIndex)
	if target == nil or not target:IsAlive() or target.GetParentEntity == nil then
		return
	end
	target = target:GetParentEntity()

	local isShiftDown = events.isShiftDown == 1
	local isCtrlDown = events.isCtrlDown == 1

	container:GiveItem(target, item, isShiftDown, isCtrlDown)
end

function Survival:OnOpenChest(events)
	local playerId = events.PlayerID

	local unit = EntIndexToHScript(events.unitIndex)
	if unit == nil or not unit:IsAlive() or unit.GetParentEntity == nil then
		return
	end
	unit = unit:GetParentEntity()

	local chest = EntIndexToHScript(events.chestIndex)
	if chest == nil or not chest:IsAlive() or chest.GetParentEntity == nil then
		return
	end
	chest = chest:GetParentEntity()

	if chest:IsChest() then
		chest:MoveToOpen(unit)
	end
end

function Survival:OnQuickMoveItem(events)
	local playerId = events.PlayerID

	local container = GetEntityByIndex(events.containerIndex)
	if container == nil then
		return
	end
	local slotIndex = events.slotIndex

	local isShiftDown = events.isShiftDown == 1
	local isCtrlDown = events.isCtrlDown == 1

	local containerOwner = container:GetOwner()
	local item = container:GetItemInSlot(slotIndex)
	if item == nil then
		return
	end

	local charges = 0
	if item:IsStackable() and item:GetCurrentCharges() > 1 then
		if isShiftDown ~= nil and isShiftDown then
			charges = math.floor(item:GetCurrentCharges()/2)
		elseif isCtrlDown ~= nil and isCtrlDown then
			charges = 1
		end
	end

	if containerOwner:IsChest() then
		if not containerOwner:IsOpen() then
			return
		end
		local operatingUnit = containerOwner:GetOperatingUnit()
		if charges > 0 then
			local targetItem = Item(item:GetName())
			if targetItem:IsPerishable() then
				targetItem.perishRemainingTime = item.perishRemainingTime
			end
			targetItem:SetCurrentCharges(charges)
			if operatingUnit:AddItem(targetItem) then
				item:SetCurrentCharges(item:GetCurrentCharges()-charges)
			else
				targetItem:Remove()
			end
			return
		end

		if operatingUnit:AddItem(item) then
			container:SetItemInSlot(nil, slotIndex)
		end
		return
	else
		local openChests = containerOwner:GetNetTable("openChests") or {}
		if #openChests == 0 then
			if containerOwner:IsHero() then
				if container == containerOwner:GetBackpack() then
					local inventory = containerOwner:GetInventory()

					if charges > 0 then
						local targetItem = Item(item:GetName())
						if targetItem:IsPerishable() then
							targetItem.perishRemainingTime = item.perishRemainingTime
						end
						targetItem:SetCurrentCharges(charges)
						if inventory:AddItem(targetItem) then
							item:SetCurrentCharges(item:GetCurrentCharges()-charges)
						else
							targetItem:Remove()
						end
						return
					end

					if inventory:AddItem(item) then
						container:SetItemInSlot(nil, slotIndex)
					end
					return
				elseif container == containerOwner:GetInventory() then
					local backpack = containerOwner:GetBackpack()

					if charges > 0 then
						local targetItem = Item(item:GetName())
						if targetItem:IsPerishable() then
							targetItem.perishRemainingTime = item.perishRemainingTime
						end
						targetItem:SetCurrentCharges(charges)
						if backpack:AddItem(targetItem) then
							item:SetCurrentCharges(item:GetCurrentCharges()-charges)
						else
							targetItem:Remove()
						end
						return
					end

					if backpack:AddItem(item) then
						container:SetItemInSlot(nil, slotIndex)
					end
					return
				end
			end
		else
			local chest = GetEntityByIndex(openChests[1])
			if chest == nil then
				return
			end

			if charges > 0 then
				local targetItem = Item(item:GetName())
				if targetItem:IsPerishable() then
					targetItem.perishRemainingTime = item.perishRemainingTime
				end
				targetItem:SetCurrentCharges(charges)
				if chest:AddItem(targetItem) then
					item:SetCurrentCharges(item:GetCurrentCharges()-charges)
				else
					targetItem:Remove()
				end
				return
			end

			if chest:AddItem(item) then
				container:SetItemInSlot(nil, slotIndex)
			end
		end
	end

end

function Survival:OnEquipOrUnequipEquipment(events)
	local playerId = events.PlayerID

	local container = GetEntityByIndex(events.containerIndex)
	if container == nil then
		return
	end
	local slotIndex = events.slotIndex

	local isShiftDown = events.isShiftDown == 1
	local isCtrlDown = events.isCtrlDown == 1

	local containerOwner = container:GetOwner()
	local item = container:GetItemInSlot(slotIndex)
	if item == nil then
		return
	end

	local charges = 0
	if item:IsStackable() and item:GetCurrentCharges() > 1 then
		if isShiftDown ~= nil and isShiftDown then
			charges = math.floor(item:GetCurrentCharges()/2)
		elseif isCtrlDown ~= nil and isCtrlDown then
			charges = 1
		end
	end

	if container:IsEquipments() then
		local funcAddItem = function(hero, item)
			local inventory = hero:GetInventory()
			local backpack = hero:GetBackpack()

			if item:IsStackable() then
				local remain = inventory:AddItemCharges(item)
				if remain > 0 then
					remain = backpack:AddItemCharges(item)
					if remain > 0 then
						if not inventory:AddItemToEmptySlot(item) then
							if not backpack:AddItemToEmptySlot(item) then
								return false
							end
						end
					end
				end
			else
				if not inventory:AddItemToEmptySlot(item) then
					if not backpack:AddItemToEmptySlot(item) then
						return false
					end
				end
			end

			return true
		end

		if charges > 0 then
			local targetItem = Item(item:GetName())
			if targetItem:IsPerishable() then
				targetItem.perishRemainingTime = item.perishRemainingTime
			end
			targetItem:SetCurrentCharges(charges)
			if funcAddItem(containerOwner, targetItem) then
				item:SetCurrentCharges(item:GetCurrentCharges()-charges)
			else
				targetItem:Remove()
			end
			return
		end

		if funcAddItem(containerOwner, item) then
			container:SetItemInSlot(nil, slotIndex)
		end
		return
	elseif item:IsEquipment() then
		local operatingUnit = containerOwner
		if containerOwner:IsChest() then
			if not containerOwner:IsOpen() then
				return
			end
			operatingUnit = containerOwner:GetOperatingUnit()
		end
		local equipments = operatingUnit:GetEquipments()

		container:SwapItems(slotIndex, equipments, item:GetEquipmentsSlot(), isShiftDown, isCtrlDown)
	end
end
